/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.webos.java.base.tree;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.json.JSONObject;
import org.webos.java.root.Log;

/**
 *
 * @author Kostya
 */
abstract public class TreeControllerItem <T, V extends TreeControllerItem>{
    
    public static final int TYPE_LEAF = 1;
    public static final int TYPE_FOLDER = 0;
    public static final int TYPE_UNKNOWN = 2;

    private T object = null;
    private TreeControllerItem parent = null;
    protected List<V> children = new ArrayList<V>();
    protected final List<V> allchildren = new ArrayList<V>();
    private boolean collapsed = true;
    private int type = TYPE_FOLDER;
    protected TreeController treeController = null;
    private String id = null;
    private Comparator comparator = null;
    private JSONObject data = new JSONObject();

    public TreeControllerItem(TreeController aController){
        super();
        treeController = aController;
    }

    public TreeControllerItem(TreeController aController, T aObject){
        super();
        treeController = aController;
        object = aObject;
    }


    abstract public void objectTOJSON(JSONObject aObject);

    public void setComparator(Comparator comparator) {
        this.comparator = comparator;
    }

    public T getObject() {
        return object;
    }

    public void setObject(T object) {
        this.object = object;
    }

    public TreeControllerItem getParent() {
        return parent;
    }

    public void setParent(TreeControllerItem parent) {
        this.parent = parent;
    }

    public boolean isCollapsed() {
        return collapsed;
    }

    public void setCollapsed(boolean collapsed) {
        this.collapsed = collapsed;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public V getChildren(int pos){
        return children.get(pos);
    }

    public V getAllChildren(int pos){
        return allchildren.get(pos);
    }

    public int getChildrenCount(){
        return children.size();
    }

    public int getAllChildrenCount(){
        return allchildren.size();
    }

    public boolean insertChild(int pos, TreeControllerItem aItem){
        if(type==TYPE_LEAF)
            return false;
        aItem.setParent(this);
        if(children.contains(aItem))
            return false;
        synchronized(allchildren){
            if(!allchildren.contains(aItem))
                allchildren.add((V)aItem);
        }
        if(!aItem.isVisible())
            return false;
        if(pos>=getChildrenCount())
            children.add((V)aItem);
        else
            children.add(pos, (V)aItem);
        treeController.itemInserted(aItem);
        return true;
    }

    public void beforeRemove(){
    }

    private void notifyRemove(){
        for (int i = 0; i < getChildrenCount(); i++) {
            TreeControllerItem ch = getChildren(i);
            ch.notifyRemove();
        }
        beforeRemove();
    }

    private boolean _remove(){
        int pos = getParent().children.indexOf(this);
        if(getParent().children.remove(this)){
            treeController.itemRemoved(this, pos);
            return true;
        }else
            return false;
    }

    public boolean remove(){
        if(getParent()==null)
            return false;
        getParent().allchildren.remove(this);
        notifyRemove();
        if(_remove()){
            return true;
        }
        return false;
    }

    public void notifyModified(){
        Log.debug(this, "notifyModified", id, isVisible());
        if(getParent()!=null){
            if(!isVisible() && getParent().children.indexOf(this)!=-1){
                //Hide element
                Log.debug(this, "item "+id+" was visible, hide now");
                _remove();
                return;
            }
            if(isVisible() && getParent().children.indexOf(this)==-1){
                //Add element
                Log.debug(this, "item "+id+" was hidden, visible now");
                getParent().appendChild(this);
                return;
            }
            if(!isVisible()){
                Log.debug(this, "item "+id+" not visible, skip");
                return;
            }
            if(getParent().getComparator()!=null){
                int currentPos = getPosition();
                int newPos = findPosition();
    //            Log.debug(this, "Modified item "+getId()+", cur: "+currentPos+", new: "+newPos);
                if(newPos>currentPos){
                    newPos--;
                }
                if(currentPos!=newPos){
                    getParent().children.remove(currentPos);
                    getParent().children.add(newPos, this);
                }
            }
        }
        treeController.itemModified(this);
    }

    @Override
    public String toString() {
        return "id = "+getId()+", colapsed = "+isCollapsed()+", type = "+getType();
    }

    public int getPosition(){
        if(getParent()!=null)
            return getParent().children.indexOf(this);
        return -1;
    }

    private Comparator getComparator() {
        return comparator;
    }

    public int findPosition(){
        if(getParent()==null)
            return 0;
        if(getParent().getComparator()!=null){
            for (int j = 0; j < getParent().getChildrenCount(); j++) {
                TreeControllerItem item = getParent().getChildren(j);
                int compresult = getParent().getComparator().compare(item, this);
//                Log.debug(this, "Compare: "+item.getId()+" and "+getId()+" = "+compresult);
                if(compresult>0)
                    return j;
            }
        }
        return getParent().getChildrenCount();
    }

    public boolean appendChild(V aItem){
        aItem.setParent(this);
        int pos = aItem.findPosition();
        return insertChild(pos, aItem);
    }

    public void clear(){
        for (int i = 0; i < allchildren.size(); i++) {
            TreeControllerItem item = allchildren.get(i);
            if(item.remove())
                i--;
        }
    }

    /**
     * @return the data
     */
    public JSONObject getData() {
        return data;
    }

    /**
     * @param data the data to set
     */
    public void setData(JSONObject data) {
        this.data = data;
    }

    public V findItem(String aID){
        for (int i = 0; i < getChildrenCount(); i++) {
            V item = getChildren(i);
            if(item.getId().equals(aID))
                return item;

        }
        return null;
    }

    public V findAllItem(String aID){
        for (int i = 0; i < getAllChildrenCount(); i++) {
            V item = getAllChildren(i);
            if(item.getId().equals(aID))
                return item;

        }
        return null;
    }

    public boolean isVisible(){
        return true;
    }
}
